/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkIni.h"
#include "MkFile.h"
#include "MkLog.h"
#include "MkUtil.h"

CMkIni::CMkIni()
{

}


Uint32 CMkIni::LoadFile(const MkString& FilePathName)
{
    MkString Content;
    Uint32 ErrorCode = CMkFile::ReadFileBuffer(FilePathName, Content);
    MkCheckErrorLog(ErrorCode, "read file :%s failed\n", FilePathName.c_str());
    return Parse(Content);
}

Uint32 CMkIni::Parse(const MkString& Content)
{
    MkString strLine;
    Uint32 nPos = 0;
    MkString AppName;
    MkMapString MapKeyValue;
    while (NoneError == CMkUtil::BufferReadLine(Content, nPos, strLine)) {
        CMkUtil::TrimString(strLine);
        if (strLine.empty()
            || CMkUtil::BeginByString(strLine, ";")
            || CMkUtil::BeginByString(strLine, "#")) {
            continue;
        }
        if (strLine.size() > 2
            && '[' == strLine.front()
            && ']' == strLine.back()) {
            if (!AppName.empty()) {
                m_MapAppKey[AppName] = MapKeyValue;
                MapKeyValue.clear();
            }
            AppName = strLine.substr(1, strLine.size() - 2);
        } else {
            MkVectorString VecString;
            CMkUtil::StringSplit(strLine, "=", VecString);
            if (VecString.size() > 1) {
                MapKeyValue[VecString[0]] = VecString[1];
            } else {
                MapKeyValue[VecString[0]] = "";
            }
        }
    }
    m_MapAppKey[AppName] = MapKeyValue;
    return NoneError;
}

Uint32 CMkIni::WriteFile(const MkString& FileName)
{
    MkString Content;
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.begin();
    for (; it != m_MapAppKey.end(); it++) {
        Content += "[" + it->first + "]\r\n";
        MkMapString::iterator itKey = it->second.begin();
        for (; itKey != it->second.end(); itKey++) {
            //add 4 space
            Content += "    " + itKey->first + "=" + itKey->second + "\r\n";
        }
    }
    return CMkFile::WriteFileBuffer(FileName, Content);
}

const MkString& CMkIni::GetProfileString(const MkString& AppName, const MkString& KeyName, const MkString& DefaultValue) const
{
    MkMap<MkString, MkMapString>::const_iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        MkMapString::const_iterator itKey = it->second.find(KeyName);
        if (itKey != it->second.end()) {
            return itKey->second;
        }
    }
    return DefaultValue;
}

Uint32 CMkIni::GetProfileUint32(const MkString& AppName, const MkString& KeyName, const Uint32& DefaultValue/* = 0*/) const
{
    MkMap<MkString, MkMapString>::const_iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        MkMapString::const_iterator itKey = it->second.find(KeyName);
        if (itKey != it->second.end()
            && !itKey->second.empty()) {
            return std::stoi(itKey->second);
        }
    }
    return DefaultValue;
}

double CMkIni::GetProfileDouble(const MkString& AppName, const MkString& KeyName, const double& DefaultValue/* = 0.0f*/) const
{
    MkMap<MkString, MkMapString>::const_iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        MkMapString::const_iterator itKey = it->second.find(KeyName);
        if (itKey != it->second.end()
            && !itKey->second.empty()) {
            return CMkUtil::SafeAtof(itKey->second.c_str());
        }
    }
    return DefaultValue;
}

BOOL CMkIni::GetProfileBoolean(const MkString& AppName, const MkString& KeyName, const BOOL& DefaultValue/* = FALSE*/) const
{
    MkMap<MkString, MkMapString>::const_iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        MkMapString::const_iterator itKey = it->second.find(KeyName);
        if (itKey != it->second.end()) {
            return "true" == itKey->second;
        }
    }
    return DefaultValue;
}

const MkString& CMkIni::GetProfileString(const MkString& AppKeyName, const MkString& DefaultValue/* = ""*/) const
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return DefaultValue;
    }
    return GetProfileString(vecString[0], vecString[1], DefaultValue);
}

Uint32 CMkIni::GetProfileUint32(const MkString& AppKeyName, const Uint32& DefaultValue/* = 0*/) const
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return DefaultValue;
    }
    return GetProfileUint32(vecString[0], vecString[1], DefaultValue);
}

double CMkIni::GetProfileDouble(const MkString& AppKeyName, const double& DefaultValue/* = 0.0f*/) const
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return DefaultValue;
    }
    return GetProfileDouble(vecString[0], vecString[1], DefaultValue);
}

BOOL CMkIni::GetProfileBoolean(const MkString& AppKeyName, const BOOL& DefaultValue/* = FALSE*/) const
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return DefaultValue;
    }
    return GetProfileBoolean(vecString[0], vecString[1], DefaultValue);
}

Uint32 CMkIni::SetProfileString(const MkString& AppName, const MkString& KeyName, const MkString& StrValue)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        it->second[KeyName] = StrValue;
    } else {
        MkMapString MapKeyValue;
        MapKeyValue[KeyName] = StrValue;
        m_MapAppKey[AppName] = MapKeyValue;
    }
    return NoneError;
}

Uint32 CMkIni::SetProfileUint32(const MkString& AppName, const MkString& KeyName, const Uint32& uValue)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        it->second[KeyName] = std::to_string(uValue);
    } else {
        MkMapString MapKeyValue;
        MapKeyValue[KeyName] = std::to_string(uValue);
        m_MapAppKey[AppName] = MapKeyValue;
    }
    return NoneError;
}

Uint32 CMkIni::SetProfileDouble(const MkString& AppName, const MkString& KeyName, const double& dValue)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        it->second[KeyName] = std::to_string(dValue);
    } else {
        MkMapString MapKeyValue;
        MapKeyValue[KeyName] = std::to_string(dValue);
        m_MapAppKey[AppName] = MapKeyValue;
    }
    return NoneError;
}

Uint32 CMkIni::SetProfileBoolean(const MkString& AppName, const MkString& KeyName, const BOOL& bValue)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        it->second[KeyName] = bValue ? "true" : "false";
    } else {
        MkMapString MapKeyValue;
        MapKeyValue[KeyName] = bValue ? "true" : "false";
        m_MapAppKey[AppName] = MapKeyValue;
    }
    return NoneError;
}

Uint32 CMkIni::SetProfileString(const MkString& AppKeyName, const MkString& StrValue)
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return InvalidParams;
    }
    return SetProfileString(vecString[0], vecString[1], StrValue);
}

Uint32 CMkIni::SetProfileUint32(const MkString& AppKeyName, const Uint32& uValue)
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return InvalidParams;
    }
    return SetProfileUint32(vecString[0], vecString[1], uValue);
}

Uint32 CMkIni::SetProfileDouble(const MkString& AppKeyName, const double& dValue)
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return InvalidParams;
    }
    return SetProfileDouble(vecString[0], vecString[1], dValue);
}

Uint32 CMkIni::SetProfileBoolean(const MkString& AppKeyName, const BOOL& bValue)
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(AppKeyName, ".", vecString);
    if (NoneError != ErrorCode
        || vecString.size() < 2) {
        return InvalidParams;
    }
    return SetProfileBoolean(vecString[0], vecString[1], bValue);
}


Uint32 CMkIni::GetProfileAppNames(MkVectorString& VecAppNames)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.begin();
    for (; it != m_MapAppKey.end(); it++) {
        VecAppNames.emplace_back(it->first);
    }
    return NoneError;
}

Uint32 CMkIni::GetProfileKeyNames(const MkString& AppName, MkVectorString& VecKeyNames)
{
    MkMap<MkString, MkMapString>::iterator it = m_MapAppKey.find(AppName);
    if (it != m_MapAppKey.end()) {
        MkMapString::iterator itKey = it->second.begin();
        for (; itKey != it->second.end(); itKey++) {
            VecKeyNames.emplace_back(itKey->first);
        }
    }
    return NoneError;
}


CMkIni::~CMkIni()
{
    m_MapAppKey.clear();
}